#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include "l0001-0/l0001-0.h"
#include "l0002-0/l0002-0.h"
#include "cJSON.h"
#include "shmfifo.h"
#include "shmstruct.h"
#include "dataxchgtable.h"
#include "xtable.h"
#include "parser.h"

#define MODNAME "[XTBL]"
extern struct l0032_dataxchgtable* __l0032_dxtable;
extern struct l0032_iniconf_parser iniconf_parser;
static int parse_xtable_iniconf_refentry(cJSON *root, struct l0032_xtable_entry *rentry);
static int is_string_equal_safe(const char *s1, const char *s2);
static int l0032_xtable_allocate_resource(struct l0032_xtable *xtable);
static void context_errmessage(cJSON *node, const char* expect_field, int type);
#define CJSON_ITEMTYPE_BOOL		"bool"
#define CJSON_ITEMTYPE_NULL		"null"
#define CJSON_ITEMTYPE_NUMBER		"number"
#define CJSON_ITEMTYPE_STRING		"string"
#define CJSON_ITEMTYPE_ARRAY		"array"
#define CJSON_ITEMTYPE_OBJECT		"dict"
#define CJSON_ITEMTYPE_UNKNOWN		"unknown"

static const char* cJSON_ItemType(int nodetype) {
	if (nodetype == cJSON_False) {
		return CJSON_ITEMTYPE_BOOL;
	}
	else if (nodetype == cJSON_True) {
		return CJSON_ITEMTYPE_BOOL;
	}
	else if (nodetype == cJSON_NULL) {
		return CJSON_ITEMTYPE_NULL;
	}
	else if (nodetype == cJSON_Number) {
		return CJSON_ITEMTYPE_NUMBER;
	}
	else if (nodetype == cJSON_String) {
		return CJSON_ITEMTYPE_STRING;
	}
	else if (nodetype == cJSON_Array) {
		return CJSON_ITEMTYPE_ARRAY;
	}
	else if (nodetype == cJSON_Object) {
		return CJSON_ITEMTYPE_OBJECT;
	}
	return CJSON_ITEMTYPE_UNKNOWN;
}

static int cJSON_ValidItem(cJSON *node, int type) {
	if (node == NULL || node->type != type) {
		return 0;
	}

	return 1;
}

static int cJSON_ValidNumber(cJSON *node) {
	if (node == NULL || node->type != cJSON_Number) {
		return 0;
	}

	return 1;
}

static int cJSON_ValidString(cJSON *node) {
	if (cJSON_ValidItem(node, cJSON_String) == 1 && node->valuestring != NULL && strlen(node->valuestring) != 0) {
		return 1;
	}
	return 0;
}

const char* l0032_xtable_dump_entry_flags(struct l0032_xtable_entry *entry) {
	static char buf[128];
	memset(buf, 0, 128);
	if (entry->flags & L0032_DXT_FLAGS_POINT_NAMED) {
		snprintf(buf, 128, "i32*");
	}
	else {
		if (entry->flags & L0032_DXT_FLAGS_POINT_I8) {
			snprintf(buf, 128, "i8");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_U8) {
			snprintf(buf, 128, "u8");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_I32) {
			snprintf(buf, 128, "i32");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_U32) {
			snprintf(buf, 128, "u32");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_I64) {
			snprintf(buf, 128, "i64");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_U64) {
			snprintf(buf, 128, "u64");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_F32) {
			snprintf(buf, 128, "f32");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_F64) {
			snprintf(buf, 128, "f64");
		}
		else if (entry->flags & L0032_DXT_FLAGS_POINT_BUF) {
			snprintf(buf, 128, "string");
		}
	}

	if (entry->flags & L0032_DXT_FLAGS_POINT_READWRITE) {
		int offset = strlen(buf);
		if (offset != 0) {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "/rw");
		}
		else {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "rw");
		}
	}
	else {
		int offset = strlen(buf);
		if (offset != 0) {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "/ro");
		}
		else {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "ro");
		}		
	}

	if (entry->flags & L0032_DXT_FLAGS_POINT_NAMED) {
		int offset = strlen(buf);
		if (offset != 0) {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "/named");
		}
		else {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "named");
		}
	}

	if (entry->flags & L0032_DXT_FLAGS_POINT_VALUEENUM) {
		int offset = strlen(buf);
		if (offset != 0) {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "/namedenum");
		}
		else {
			snprintf(buf + strlen(buf), 128 - strlen(buf), "namedenum");
		}
	}

	return buf;
}

void l0032_xtable_dump(struct l0032_xtable *xtable) {
	if (xtable != NULL) {
		int i, j, k;
		uint8_t *cache = NULL;
		size_t cachesz = 0;
		printf("**********************************************\n");
		printf("* app name: %s\n", xtable->appname);
		printf("* parser library: %s\n", xtable->parselib);
		for (i = 0;i < xtable->nentries;i ++) {
			struct l0032_xtable_entry *entry = &xtable->entries[i];
			size_t sz = l0032_entry_get_size(entry->hentry);
			int npoints = 0;
			if (sz != 0) {
				if (sz >= cachesz) {
					if (cache != NULL) {
						free(cache);
					}
					cache = zmalloc(cachesz);
					if (cache == NULL) {
						printf("\n allocate cache size %zu failed\n", cachesz);
						return;
					}
					cachesz = sz;
				}

				if (l0032_entry_readpoints(entry->hentry, 0, &npoints, cache, cachesz) == 0) {
					printf("- [%s]: %s\n", entry->name, entry->desc);

					for (j = 0;j < entry->npoints;j ++) {
						struct l0032_xtable_namedpoint *namedpoint = &entry->namedpoints[j];
						if (entry->flags & L0032_DXT_FLAGS_POINT_VALUEENUM) {
							int val = ((int32_t*)cache)[j];
							int valfound = 0;
							printf("-- [%s]: %s\n", namedpoint->name, namedpoint->desc);
							for (k = 0;k < namedpoint->nvalues;k ++) {
								if (namedpoint->valueenum[k].val == val) {
									valfound = 1;
								}
							}
							if (valfound == 0) {
								printf("[%d]UnKnown*\n", val);
							}
							for (k = 0;k < namedpoint->nvalues;k ++) {
								if (namedpoint->valueenum[k].val == val) {
									printf("[%d]%s*\n", namedpoint->valueenum[k].val, namedpoint->valueenum[k].valdesc);
								}
								else {
									printf("[%d]%s\n", namedpoint->valueenum[k].val, namedpoint->valueenum[k].valdesc);
								}
							}
						}
						else {
							if (j % 8 == 0 && j != 0) {
								printf("\n");
							}
							if (entry->flags & L0032_DXT_FLAGS_POINT_I8) {
								printf("[%d]%d ", j, ((uint8_t*)cache)[j]);
							}
							else if (entry->flags & L0032_DXT_FLAGS_POINT_U8) {
								printf("[%d]%u  ", j, ((uint8_t*)cache)[j]);
							}
							else if (entry->flags & L0032_DXT_FLAGS_POINT_I32) {
								printf("[%d]%d ", j, ((int32_t*)cache)[j]);
							}
							else if (entry->flags & L0032_DXT_FLAGS_POINT_U32) {
								printf("[%d]%u ", j, ((uint32_t*)cache)[j]);
							}
							else if (entry->flags & L0032_DXT_FLAGS_POINT_I64) {
								printf("[%d]%lld ", j, ((long long int*)cache)[j]);
							}
							else if (entry->flags & L0032_DXT_FLAGS_POINT_U64) {
								printf("[%d]%llu ", j, ((long long unsigned int*)cache)[j]);
							}
							else if (entry->flags & L0032_DXT_FLAGS_POINT_F32) {
								printf("[%d]%.3f ", j, ((float*)cache)[j]);
							}
							else if (entry->flags & L0032_DXT_FLAGS_POINT_F64) {
								printf("[%d]%.3f ", j, ((double*)cache)[j]);
							}
							// else if (entry->flags & L0032_DXT_FLAGS_POINT_BUF) {
							// 	snprintf(buf, 128, "string");
							// }
						}
					}
					printf("\n");

				}
				else {
					printf("entrycache read falied\n");
				}
			}

		}
		
	}
}

// static int cJSON_isStringEqual(cJSON *node, const char *s) {
// 	if (cJSON_ValidString(node)) {
// 		return is_string_equal_safe(node->valuestring, s);
// 	}
// 	return 0;
// }

static int parse_xtable_iniconf_refentry(cJSON *root, struct l0032_xtable_entry *rentry)
{
	int retval = -1;

	return retval;
}


static int is_string_equal_safe(const char *s1, const char *s2)
{
	if (s1 != NULL && s2 != NULL) {
		size_t n = strlen(s1);
		if (n == strlen(s2) && strncmp(s1, s2, n) == 0) {
			return 1;
		}
	}
	return 0;
}

static int l0032_xtable2dataxchtable_type(struct l0032_xtable_entry *entry)
{
	if (entry == NULL) {
		return -1;
	}
	if (entry->flags & L0032_DXT_FLAGS_POINT_I8) {
		return L0032_DXTABLE_FLAGS_DATAI8TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_U8) {
		return L0032_DXTABLE_FLAGS_DATAU8TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_I32) {
		return L0032_DXTABLE_FLAGS_DATAI32TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_U32) {
		return L0032_DXTABLE_FLAGS_DATAU32TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_I64) {
		return L0032_DXTABLE_FLAGS_DATAI64TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_U64) {
		return L0032_DXTABLE_FLAGS_DATAU64TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_F32) {
		return L0032_DXTABLE_FLAGS_DATAF32TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_F64) {
		return L0032_DXTABLE_FLAGS_DATAF64TABLE;
	}
	else if (entry->flags & L0032_DXT_FLAGS_POINT_BUF) {
		return L0032_DXTABLE_FLAGS_DATAI8TABLE;
	}

	return -1;
}

static int parse_xtable_conf_pointlist(cJSON *point, struct l0032_xtable_entry *entry, struct l0032_xtable_namedpoint *namedpoint)
{
	int retval = -1;
	int i;
	cJSON *valueenum, *node;

	// name
	CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_NAME);
	node = cJSON_GetObjectItem(point, L0032_DXT_ENTRY_FIELD_NAME);
	if(cJSON_ValidString(node)) {
		namedpoint->flags |= L0032_DXT_FLAGS_POINT_NAMED;
		snprintf(namedpoint->name, L0032_DXT_NAME_MAX_LEN, "%s", node->valuestring);
		ERRSYS_INFOPRINT("namedpoint %s\n", namedpoint->name);
	}
	else {
		context_errmessage(node, L0032_DXT_ENTRY_FIELD_NAME, cJSON_String);
		goto err;		
	}

	// desc.
	CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_DESC);
	node = cJSON_GetObjectItem(point, L0032_DXT_ENTRY_FIELD_DESC);
	if(cJSON_ValidString(node)){
		snprintf(namedpoint->desc, L0032_DXT_DESC_MAX_LEN, "%s", node->valuestring);
		ERRSYS_INFOPRINT("desc %s\n", namedpoint->desc);
	}
	else {
		context_errmessage(node, L0032_DXT_ENTRY_FIELD_DESC, cJSON_String);
		goto err;		
	}
	namedpoint->nvalues = 0;

	//enum
	node = cJSON_GetObjectItem(point, L0032_DXT_ENTRY_FIELD_VALUENUM);
	if (node != NULL) {
		CONTEXT_PUSH(L0032_DXT_ENTRY_FIELD_VALUENUM);
		if (node->type == cJSON_Array) {
			context_errmessage(node, L0032_DXT_ENTRY_FIELD_VALUENUM, cJSON_Object);
			goto err;
		}
		// entry->flags |= L0032_DXT_FLAGS_POINT_VALUEENUM;
		namedpoint->nvalues = cJSON_GetArraySize(node);
		namedpoint->valueenum = zmalloc(sizeof(struct l0032_xtable_valueenum) * namedpoint->nvalues);
		ERRSYS_INFOPRINT("namedpoint %d values\n", namedpoint->nvalues);
		if (namedpoint == NULL) {
			CONTEXT_ERRMESSAGE("fail to malloc %d enums for point", namedpoint->nvalues);
			ERRSYS_FATALPRINT("fail to malloc %d enums for point\n", namedpoint->nvalues);
			goto err;
		}
		if (namedpoint->nvalues) {
			namedpoint->flags |= L0032_DXT_FLAGS_POINT_VALUEENUM;
		}
		for (i = 0;i < namedpoint->nvalues;i ++) {
			CONTEXT_PUSH("valueenum[%d]", i);
			valueenum = cJSON_GetArrayItem(node, i);
			if (valueenum) {
				snprintf(namedpoint->valueenum[i].valdesc, L0032_DXT_DESC_MAX_LEN, valueenum->string);
				namedpoint->valueenum[i].val = valueenum->valueint;
				ERRSYS_INFOPRINT("namedpoint value %d=(%s)\n", namedpoint->valueenum[i].val, namedpoint->valueenum[i].valdesc);
			}
			else {
				context_errmessage(valueenum, L0032_DXT_ENTRY_FIELD_VALUENUM, cJSON_Object);
				goto err;
			}
			CONTEXT_POP();
		}
		CONTEXT_POP();
	}
	retval = 0;
err:
	if (retval < 0) {
		free(namedpoint->valueenum);
	}
	return retval;
}

static void context_errmessage(cJSON *node, const char* expect_field, int type)
{
	if (node == NULL) {
		CONTEXT_ERRMESSAGE("missing field \"%s\"", expect_field);
		ERRSYS_FATALPRINT("missing field \"%s\"\n", expect_field);
	}
	else if (node->type != type) {
		CONTEXT_ERRMESSAGE("invalid type \"%s\" of field \"%s\", expecting \"%s\"", cJSON_ItemType(node->type), expect_field, cJSON_ItemType(type));
		ERRSYS_FATALPRINT("invalid type \"%s\" of field \"%s\", expecting \"%s\"\n", cJSON_ItemType(node->type), expect_field, cJSON_ItemType(type));
	}
	else {
		CONTEXT_ERRMESSAGE("invalid value for field \"%s\"", expect_field);
		ERRSYS_FATALPRINT("invalid value for field \"%s\"\n", expect_field);
	}
}

static int parse_xtable_conf_entry(cJSON *root, struct l0032_xtable_entry *entry)
{
	int retval = -1;
	int i;
	int namedpoint = 0, unnamedpoint = 0;

	cJSON *node, *point;
	//clear the flags
	entry->flags = 0;
	// name
	CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_NAME);
	node = cJSON_GetObjectItem(root, L0032_DXT_ENTRY_FIELD_NAME);
	if(cJSON_ValidString(node)) {
		snprintf(entry->name, L0032_DXT_NAME_MAX_LEN, "%s", node->valuestring);
		ERRSYS_INFOPRINT("entry %s is \"%s\"\n", L0032_DXT_ENTRY_FIELD_NAME, entry->name);
	}
	else {
		context_errmessage(node, L0032_DXT_ENTRY_FIELD_NAME, cJSON_String);
		goto err;
	}

	// desc.
	//printf("parse entry desc \n");
	CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_DESC);
	node = cJSON_GetObjectItem(root, L0032_DXT_ENTRY_FIELD_DESC);
	if(cJSON_ValidString(node)){
		snprintf(entry->desc, L0032_DXT_DESC_MAX_LEN, "%s", node->valuestring);
		ERRSYS_INFOPRINT("entry %s is \"%s\"\n", L0032_DXT_ENTRY_FIELD_DESC, entry->desc);
	}
	else {
		context_errmessage(node, L0032_DXT_ENTRY_FIELD_DESC, cJSON_String);
		goto err;
	}

	// datatype.
	//printf("parse entry datatype \n");
	CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_TYPE);
	node = cJSON_GetObjectItem(root, L0032_DXT_ENTRY_FIELD_TYPE);
	if (cJSON_ValidString(node)) {
		if (is_string_equal_safe(node->valuestring, L0032_DXT_ENTRY_FIELDVALUE_I8)) {
			entry->flags |= L0032_DXT_FLAGS_POINT_I8;
			ERRSYS_INFOPRINT("entry %s is \"%s\"\n", L0032_DXT_ENTRY_FIELD_TYPE, node->valuestring);
		}
		else if (is_string_equal_safe(node->valuestring, L0032_DXT_ENTRY_FIELDVALUE_U8)) {
			entry->flags |= L0032_DXT_FLAGS_POINT_U8;
		}
		else if (is_string_equal_safe(node->valuestring, L0032_DXT_ENTRY_FIELDVALUE_I32)) {
			entry->flags |= L0032_DXT_FLAGS_POINT_I32;
		}
		else if (is_string_equal_safe(node->valuestring, L0032_DXT_ENTRY_FIELDVALUE_U32)) {
			entry->flags |= L0032_DXT_FLAGS_POINT_U32;
		}
		else if (is_string_equal_safe(node->valuestring, L0032_DXT_ENTRY_FIELDVALUE_I64)) {
			entry->flags |= L0032_DXT_FLAGS_POINT_I64;
		}
		else if (is_string_equal_safe(node->valuestring, L0032_DXT_ENTRY_FIELDVALUE_U64)) {
			entry->flags |= L0032_DXT_FLAGS_POINT_U64;
		}
		else {
			CONTEXT_ERRMESSAGE("invalid entry type(%s), should be i8/u8/i32/u32/i64/u64", node->valuestring);
			ERRSYS_FATALPRINT("invalid entry type(%s), should be i8/u8/i32/u32/i64/u64\n", node->valuestring);
			goto err;
		}
		ERRSYS_INFOPRINT("entry %s is \"%s\"\n", L0032_DXT_ENTRY_FIELD_TYPE, node->valuestring);
	}
	else {
		context_errmessage(node, L0032_DXT_ENTRY_FIELD_TYPE, cJSON_String);
		goto err;
	}

	// readwrite.
	CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_READWRITE);
	node = cJSON_GetObjectItem(root, L0032_DXT_ENTRY_FIELD_READWRITE);
	if(cJSON_ValidString(node)){
		if (is_string_equal_safe(node->valuestring, L0032_DXT_FIELDVALUE_RW)) {
			entry->flags |= L0032_DXT_FLAGS_POINT_READWRITE;
		}
		else if (is_string_equal_safe(node->valuestring, L0032_DXT_FIELDVALUE_RO) == 0){
			CONTEXT_ERRMESSAGE("invalid entry type(%s), should be ro/rw", node->valuestring);
			ERRSYS_FATALPRINT("invalid entry type(%s), should be ro/rw\n", node->valuestring);
			goto err;
		}
	}
	else {
		context_errmessage(node, L0032_DXT_ENTRY_FIELD_READWRITE, cJSON_String);
		goto err;
	}

	// npoints.
	CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_POINTCOUNT);
	node = cJSON_GetObjectItem(root, L0032_DXT_ENTRY_FIELD_POINTCOUNT);
	if(node){
		if (cJSON_ValidNumber(node)) {
			//TODO:
			unnamedpoint = 1;
			entry->npoints = node->valueint;
		}
		else {
			context_errmessage(node, L0032_DXT_ENTRY_FIELD_POINTCOUNT, cJSON_Number);
			goto err;
		}

	}
	else {
		CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_POINTLISTCOUNT);
		node = cJSON_GetObjectItem(root, L0032_DXT_ENTRY_FIELD_POINTLISTCOUNT);
		if (node) {
			if (cJSON_ValidNumber(node)) {
				int pointlistcount = node->valueint;
				ERRSYS_INFOPRINT("point list count %d\n", pointlistcount);
				namedpoint = 1;
				CONTEXT_EXPECT(L0032_DXT_ENTRY_FIELD_POINTLIST);
				node = cJSON_GetObjectItem(root, L0032_DXT_ENTRY_FIELD_POINTLIST);
				if (node != NULL) {
					int npoints = cJSON_GetArraySize(node);
					entry->npoints = npoints * pointlistcount;
					entry->namedpoints = zmalloc(sizeof(struct l0032_xtable_namedpoint) * entry->npoints);
					if (entry->namedpoints == NULL) {
						ERRSYS_FATALPRINT("fail to malloc %d points\n", entry->npoints);
						goto err;
					}
					for (i = 0;i < npoints;i ++) {
						point = cJSON_GetArrayItem(node, i);
						// entry->flags |= L0032_DXT_FLAGS_POINT_NAMED;
						CONTEXT_PUSH("POINT[%d]", i);
						ERRSYS_INFOPRINT("parsing point #%d\n", i);
						if (parse_xtable_conf_pointlist(point, entry, &entry->namedpoints[i]) != 0) {
							goto err;
						}
						CONTEXT_POP();
					}			
				}
				else {
					context_errmessage(node, L0032_DXT_ENTRY_FIELD_POINTLIST, cJSON_Array);
					goto err;
				}
			}
			else {
				context_errmessage(node, L0032_DXT_ENTRY_FIELD_POINTLISTCOUNT, cJSON_Number);
				goto err;
			}
		}
	
		if (namedpoint == 0 && unnamedpoint == 0) {
			CONTEXT_ERRMESSAGE("missing either pointcount or pointlistcount %s", L0032_DXT_ENTRY_FIELD_NAME);
			ERRSYS_FATALPRINT("missing either pointcount or pointlistcount %s\n", L0032_DXT_ENTRY_FIELD_NAME);
			goto err;
		}
	}

	retval = 0;
err:
	if (retval < 0) {
		free(entry->namedpoints);
	}
	return retval;
}

static int parse_xtable_conf(struct l0032_xtable* xtable, const char *json)
{
	int retval = -1;
	int i, nentries_valid, nentries;

	cJSON *root = NULL;
	cJSON *node, *entries, *entry;

	l0032_reinit_iniconf_parser(&iniconf_parser, 16);
	
	root = cJSON_Parse(json);
	if(root == NULL){
		ERRSYS_FATALPRINT("wrong format of json in parsing iniconf\n");
		goto err1;
	}
	CONTEXT_PUSH("<root>");

	// appname.
	CONTEXT_EXPECT(L0032_DXT_DXTABLE_FIELD_APPNAME);
	node = cJSON_GetObjectItem(root, L0032_DXT_DXTABLE_FIELD_APPNAME);
	if(cJSON_ValidString(node)){
		snprintf(xtable->appname, L0032_DXT_NAME_MAX_LEN, "%s", node->valuestring);
		ERRSYS_INFOPRINT("%s is \"%s\"\n", L0032_DXT_DXTABLE_FIELD_APPNAME, xtable->appname);
	}
	else {
		context_errmessage(node, L0032_DXT_DXTABLE_FIELD_APPNAME, cJSON_String);
		goto err;
	}

	// parselib.
	CONTEXT_EXPECT(L0032_DXT_DXTABLE_FIELD_PARSELIB);
	node = cJSON_GetObjectItem(root, L0032_DXT_DXTABLE_FIELD_PARSELIB);
	if(cJSON_ValidString(node)){
		snprintf(xtable->parselib, L0032_DXT_NAME_MAX_LEN, "%s", node->valuestring);
		ERRSYS_INFOPRINT("%s is \"%s\"\n", L0032_DXT_DXTABLE_FIELD_APPNAME, xtable->parselib);
	}
	// else {
	// 	context_errmessage(node, L0032_DXT_DXTABLE_FIELD_PARSELIB, cJSON_String);
	// 	goto err;		
	// }

	// entrylist.
	CONTEXT_EXPECT(L0032_DXT_DXTABLE_FIELD_ENTRYLIST);
	entries = cJSON_GetObjectItem(root, L0032_DXT_DXTABLE_FIELD_ENTRYLIST);
	if(entries == NULL){
		context_errmessage(node, L0032_DXT_DXTABLE_FIELD_PARSELIB, cJSON_String);
		goto err;		
	}
	
	nentries = cJSON_GetArraySize(entries);
	nentries_valid = 0;
	if (nentries > L0032_DXT_APP_ENTRY_MAX_NUM) {
		CONTEXT_ERRMESSAGE("too many entries(%d)", nentries);
		ERRSYS_FATALPRINT("too many entries(%d)\n", nentries);
		goto err;
	}
	ERRSYS_INFOPRINT("total %d entries\n", nentries);

	xtable->entries = zmalloc(sizeof(struct l0032_xtable_entry) * nentries);
	if(xtable->entries == NULL){
		ERRSYS_FATALPRINT("fail to malloc %d entries for entry_list\n", nentries);
		goto err;
	}
	CONTEXT_PUSH(entries->string);
	for(i = 0; i < nentries; i++) {
		entry = cJSON_GetArrayItem(entries, i);
		node = cJSON_GetObjectItem(entry, L0032_DXT_ENTRY_FIELD_ENABLE);
		if (cJSON_ValidNumber(node)) {
			ERRSYS_INFOPRINT("parsing entry #%d ...\n", i);
			CONTEXT_PUSH("entry[%d]", i);
			if(parse_xtable_conf_entry(entry, &xtable->entries[nentries_valid]) != 0){
				ERRSYS_FATALPRINT("parsing entry[%d] failed\n", i);
				goto err;
			}
			CONTEXT_POP();

			nentries_valid ++;
		}
		else {
			context_errmessage(node, L0032_DXT_ENTRY_FIELD_ENABLE, cJSON_Number);
			goto err;
		}

	}
	xtable->nentries = nentries_valid;
	if (nentries_valid == 0) {
		CONTEXT_ERRMESSAGE("no entries enabled");
		goto err;
	}

	// reference entry.
	entries = cJSON_GetObjectItem(root, L0032_DXT_DXTABLE_FIELD_REFERLIST);
	if(entries != NULL){
		nentries = cJSON_GetArraySize(entries);
		nentries_valid = 0;
		if (nentries > L0032_DXT_APP_REFENTRY_MAX_NUM) {
			ERRSYS_FATALPRINT("too many refentries(%d)\n", nentries);
			goto err;
		}

		xtable->refentries = zmalloc(sizeof(struct l0032_xtable_entry) * nentries);
		if(xtable->refentries == NULL){
			ERRSYS_FATALPRINT("fail to malloc %d refentries\n", nentries);
			goto err;
		}
		for(i = 0; i < nentries ;i++){
			entry = cJSON_GetArrayItem(entries, i);
			if(parse_xtable_iniconf_refentry(entry, &xtable->refentries[nentries_valid]) != 0){
				ERRSYS_FATALPRINT("parsing dxt refentry#%d failed\n", i);
				goto err;
			}
			nentries_valid++;
		}
		xtable->nrefentries = nentries_valid;
	}

	retval = l0032_xtable_allocate_resource(xtable);

err:
	if (retval < 0) {
		free(xtable->entries);
		free(xtable->refentries);
		l0032_parser_dump(&iniconf_parser);
	}
err1:
	if( root != NULL){
		cJSON_Delete(root);
	}
	return retval;
}

static int l0032_xtable_allocate_resource(struct l0032_xtable *xtable) 
{
	int i;
	int dxterrno;

	for (i = 0;i < xtable->nentries;i ++) {
		struct l0032_xtable_entry *entry = &xtable->entries[i];
		int type = l0032_xtable2dataxchtable_type(entry);
		// namedpoint type is forced to be int32
		if (entry->flags & L0032_DXT_FLAGS_POINT_NAMED) {
			entry->flags &= ~(L0032_DXT_FLAGS_POINT_NUMBERTYPE);
			entry->flags |= L0032_DXT_FLAGS_POINT_I32;
		}
		entry->hentry = l0032_entry_allocate(entry->name, type, entry->npoints, &dxterrno);
		if(!l0032_is_valid_entryhandle(entry->hentry)) {
			ERRSYS_FATALPRINT("allocate entry for %s failed\n", entry->name);
			return -1;
		}
	}

	return 0;
}

int l0032_xtable_load_conf(struct l0032_xtable *xtable, const char* iniconf) {
	FILE *fp = NULL;
	char *buffer = NULL;
	int filesize = 0;
	int retval = -1;

	if(xtable == NULL || iniconf == NULL){
		ERRSYS_FATALPRINT("xtable or iniconf is NULL\n");
		return -1;
	}

	memset(xtable, 0, sizeof(struct l0032_xtable));

	fp = fopen(iniconf, "r");
	if(fp == NULL){
		ERRSYS_FATALPRINT("fopen failed, filepath=%s, err:%s\n", iniconf, strerror(errno));
		goto err1;
	}

	fseek(fp, 0, SEEK_END);
	filesize = ftell(fp);

	if(filesize < 2){
		ERRSYS_FATALPRINT("invalid file(%s) length(%d)\n", iniconf, filesize);
		goto err1;
	}

	buffer = (char *)malloc(filesize *sizeof(char));
	if(buffer == NULL){
		ERRSYS_FATALPRINT("fail to malloc %d for buffer\n", filesize);
		goto err1;
	}

	fseek(fp, 0, SEEK_SET);
	if(fread(buffer, filesize, sizeof(char), fp) < 0){
		ERRSYS_FATALPRINT("read %s failed, err:%s\n", iniconf, strerror(errno));
		goto err1;
	}

	if(parse_xtable_conf(xtable, buffer) != 0){
		goto err1;
	}

	retval = 0;
err1:
	if(fp != NULL)
		fclose(fp);
	if(buffer != NULL)
		free(buffer);
	return retval;
}

void l0032_xtable_dump_conf(struct l0032_xtable *xtable) {
	int indent = 0;
	int i, j, k;
	printf("app name: %s\n", xtable->appname);
	printf("parse lib: %s\n", xtable->parselib);

	for (i = 0;i < xtable->nentries;i ++) {
		struct l0032_xtable_entry *entry = &xtable->entries[i];
		indent = 2;
		printf("----------entry[%d]----------\n", i);
		printf("%*s name: %s\n", indent, "", entry->name);
		printf("%*s desc: %s\n", indent, "", entry->desc);
		printf("%*s flags: %s\n", indent, "", l0032_xtable_dump_entry_flags(entry));
		if (entry->flags & L0032_DXT_FLAGS_POINT_NAMED) {
			indent = 4;
			for (j = 0;j < entry->npoints;j ++) {
				struct l0032_xtable_namedpoint *namedpoint = &entry->namedpoints[j];
				printf("---------point[%d]----------\n", j);
				printf("%*s name: %s\n", indent, "", namedpoint->name);
				printf("%*s desc: %s\n", indent, "", namedpoint->desc);
				if (entry->flags & L0032_DXT_FLAGS_POINT_VALUEENUM) {
					printf("---------valueenum(%d)----------\n", namedpoint->nvalues);
					indent = 6;
					for (k = 0;k < namedpoint->nvalues;k ++) {
						struct l0032_xtable_valueenum *valueenum = &namedpoint->valueenum[k];
						printf("%*s [%d]%d: %s\n", indent, "", k, (int)valueenum->val, valueenum->valdesc);				
					}
				}
			}
			printf("\n");
		}
	}
}

int l0032_xtable_write(entry_handle hentry, int pointno, void* addr) {
	int retval = -1;
	if (addr != NULL) {
		retval = l0032_entry_write(hentry, pointno, addr);
	}

	return retval;
}

int l0032_xtable_read(entry_handle hentry, int pointno, void* addr, size_t sz) {
	int retval = -1;
	if (addr != NULL && sz > 0) {
		retval = l0032_entry_read(hentry, pointno, addr, sz);
	}

	return retval;
}


struct l0032_xtable * l0032_xtable_open(const char* shmname, int bcreate) {
    const char* dxtname = L0032_DXTABLE_NAME;
	struct l0032_xtable *xtable = zmalloc(sizeof(struct l0032_xtable));

    if (xtable == NULL) {
        goto err1;
    }

    if (shmname != NULL) {
        dxtname = shmname;
    }
	// printf("l0032_xtable_open %s sz %zu\n", dxtname, xtable->sz);
    if (l0032_dataxchgtable_open(dxtname, &xtable->sz, bcreate) != 0) {
		free(xtable);
		xtable = NULL;
	}

err1:
	return xtable;
}

void l0032_xtable_close(void) {
    l0032_dataxchgtable_close();
}
